﻿namespace LiteBlog.Components
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Security;
    using LiteBlog.Common;
    using LiteBlog.Common.Entities;
    using LiteBlog.XmlProviders;
    using LiteBlog.Components.Contracts;
    using LiteBlog.Components.Enums;
    using System.Web;
    using LiteBlog.Common.Components;
    using Repositories.Contracts;

    public class AuthorComp : IAuthorComp
    {
        public MethodResult Unlock(string authorID)
        {
            MembershipUser user = Membership.GetUser(authorID);
            user.UnlockUser();
            return MethodResult.UnlockSuccess;
        }

        public IEnumerable<Author> Get()
        {
            var authors = new List<Author>();
            foreach (MembershipUser user in Membership.GetAllUsers())
            {
                Author author = new Author();
                author.ID = user.UserName;
                author.Email = user.Email;
                author.Locked = user.IsLockedOut;
                var customUser = user as CustomMembershipUser;
                if (customUser != null)
                {
                    author.Name = customUser.DisplayName;
                    author.IsPrimary = customUser.IsPrimary;
                    author.Enabled = customUser.Enabled;
                    author.Url = customUser.Url;
                }
                authors.Add(author);
            }

            return authors;
        }

        public Author Get(string id)
        {
            return Get().SingleOrDefault(a => a.ID == id);
        }

        public MethodResult Create(Author author)
        {
            var user = Membership.GetUser(author.ID);
            if (user != null)
                return MethodResult.DuplicateId;

            var userName = Membership.GetUserNameByEmail(author.Email);
            if (!string.IsNullOrEmpty(userName))
                return MethodResult.DuplicateEmail;

            user = Membership.CreateUser(author.ID, ConfigComp.DefaultPassword, author.Email);
            if (user != null)
            {
                var customUser = new CustomMembershipUser(user, author.Name);
                customUser.IsPrimary = author.IsPrimary;
                customUser.Enabled = author.Enabled;
                customUser.Url = author.Url ?? string.Empty;
                Membership.UpdateUser(customUser);
            }
            return user != null ? MethodResult.CreateSuccess : MethodResult.Failure;
        }

        public MethodResult Update(string olid, Author author)
        {
          
            bool success = false;
            if (author.ID != olid)
            {
                var newUser = Membership.GetUser(author.ID);
                if (newUser != null)
                    return MethodResult.DuplicateId;
            }

            // check for duplicate email
            MembershipUser oldUser = Membership.GetUser(olid);
            if (oldUser.Email != author.Email)
            {
                var userName = Membership.GetUserNameByEmail(author.Email);
                if (!string.IsNullOrEmpty(userName))
                    return MethodResult.DuplicateEmail;
            }

            if (author.ID != olid)
            {
                // change the author ID (lot of checks)
                var newUser = Membership.GetUser(author.ID);
                if (newUser != null)
                    return MethodResult.DuplicateId;

                string password = oldUser.GetPassword();
                Membership.DeleteUser(olid);

                var user = Membership.CreateUser(author.ID, password, author.Email);
                if (user != null)
                {
                    var customUser = new CustomMembershipUser(user, author.Name);
                    customUser.Enabled = author.Enabled;
                    customUser.IsPrimary = author.IsPrimary;
                    customUser.Url = author.Url ?? string.Empty;
                    Membership.UpdateUser(customUser);

                    ChangeAuthor(olid, user.UserName);
                }
                success = user != null;
            }
            else
            {
                success = Update(author);
            }

            return success ? MethodResult.UpdateSuccess : MethodResult.Failure;
        }

        public MethodResult Delete(string id)
        {
            if (Get(id).IsPrimary)
                return MethodResult.PrimaryRecord;

            Membership.DeleteUser(id);

            string primaryAuthor = GetPrimaryAuthor().ID;
            ChangeAuthor(id, primaryAuthor);
            
            return MethodResult.DeleteSuccess;
        }


        public MethodResult Disable(string id, bool enable = false)
        {
            var author = Get(id);
            author.Enabled = enable;
            return Update(author) ? (enable ? MethodResult.EnableSuccess : MethodResult.DisableSuccess) : MethodResult.Failure;
        }

        public MethodResult MakePrimary(string id)
        {
            bool success = false;
            var author = Get(id);
            var primaryAuthor = GetPrimary();
            primaryAuthor.IsPrimary = false;
            success = Update(primaryAuthor);
            if (success)
            {
                author.IsPrimary = true;
                success = Update(author);
            }

            return success ? MethodResult.PrimarySuccess : MethodResult.Failure;
        }

        private Author GetPrimary()
        {
            return Get().SingleOrDefault(a => a.IsPrimary);
        }

        // no change in author id
        private bool Update(Author author)
        {
            var user = Membership.GetUser(author.ID);
            if (user != null)
            {
                var customUser = new CustomMembershipUser(user, author.Name);
                customUser.Email = author.Email;
                customUser.Enabled = author.Enabled;
                customUser.IsPrimary = author.IsPrimary;
                customUser.Url = author.Url ?? string.Empty;
                Membership.UpdateUser(customUser);
            }

            return user!=null;
        }


        public MethodResult ValidateUser(string userName, string password)
        {
            bool valid = Membership.ValidateUser(userName, password);
            if (valid)
            {
                var author = Get(userName);
                valid = author != null;
                if (valid)
                    valid = author.Enabled;

                if (valid)
                    HttpContext.Current.Session["Admin"] = author.IsPrimary; // hack for now!
            }
            return valid ? MethodResult.LoginSuccess : MethodResult.LoginFailure;
        }

        private Author GetPrimaryAuthor()
        {
            return Get().Single(a => a.IsPrimary);
        }


        public MethodResult ChangePassword(string userName, string oldPassword, string newPassword)
        {
            var user = Membership.GetUser(userName);
            return user.ChangePassword(oldPassword, newPassword) ? MethodResult.ChangePasswordSuccess : MethodResult.Failure;
        }

        public AuthorComp(IBlogRepository blogRepo, IPostRepository postRepo) : base()
        {
            _blogRepo = blogRepo;
            _postRepo = postRepo;
        }

        private void ChangeAuthor(string olid, string newid)
        {
            var postInfos = _blogRepo
                .Get()
                .Where(pi => pi.Author.Equals(olid));

            foreach(var postInfo in postInfos)
            {
                var post = _postRepo.Load(postInfo.FileID);
                post.Author = newid;
                _postRepo.Save(post);
            }

            if (postInfos.Any())
            {
                _blogRepo.ChangeAuthor(olid, newid);
            }
        }

        private IBlogRepository _blogRepo;
        private IPostRepository _postRepo;
    }
}